#include <QStandardPaths>
#include <QDir>
#include <QFile>
#include <QJsonObject>
#include <QJsonDocument>
#include <QFileInfo>

#include "datacenter.h"


namespace model{

// 这里不先进行创建的原因是
// 必须得先QApplication实例化后才进行这里的实例
// datacenter* datacenter::instance = new datacenter();
datacenter* datacenter::instance = nullptr;

// 饿汉模式，程序启动就创建
datacenter *datacenter::getInstance()
{
    if(instance == nullptr)
    {
        instance = new datacenter();
    }
    return instance;
}

datacenter::datacenter()
    :netClient(this)
{
    // 此处只负责把hash成员给进行new出实例，其他的暂时不进行初始化
    // 主要是为了使用nullptr来表示非法状态
    // 对于hash来说，关心key和value是否存在就可以判断该值是否有效
    memberList = new QHash<QString, QList<UserInfo>>();
    recentMessages = new QHash<QString,QList<Message>>();
    unreadMessagesCount = new QHash<QString,int>();

    // 加载数据
    this->loadDataFile();
}

datacenter::~datacenter()
{
    // 是否所有成员
    // 此处不必判断是否为nullptr
    // 因为在C++11中，针对nullptr进行delete是合法的
    delete myself;
    delete friendList;
    delete chatSessionInfoList;
    delete memberList;
    delete applyList;
    delete recentMessages;
    delete unreadMessagesCount;
    delete searchFriendResult;
}

void datacenter::initDataFile()
{
    // 这里主要是确定文件存放的位置和类型
    // 为了让别人也可以直接使用
    // 这里我们采用windows中每个用户下都有的appData文件来存放
    // 目录
    QString basePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
    // 文件
    QString filePath = basePath + "/ChatClient.json";
    LOG_DEBUG << "filePath:" << filePath;

    // 创建目录
    QDir dir;
    if(!dir.exists(basePath))
    {
        dir.mkdir(basePath);
    }

    // 以写的形式打开文件，如果文件还未创建会自动创建
    QFile file(filePath);
    if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        LOG_ERROR << "文件打开失败！" << file.errorString();
        return;
    }

    // 打开成功，写入初始值
    QString data = "{\n\n}";
    file.write(data.toUtf8());

    // 关闭文件
    file.close();
}

// 保存数据，服务器传来的数据保存到本地
void datacenter::saveDataFile()
{
    QString filePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/ChatClient.json";

    // 打开文件
    QFile file(filePath);
    if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        LOG_ERROR << "文件打开失败！" << file.errorString();
        return;
    }

    // 序列化成json格式
    QJsonObject JsonObj;
    JsonObj["loginSessionId"] = loginSessionId;
    QJsonObject unreadJson;
    for(auto it = unreadMessagesCount->begin();it != unreadMessagesCount->end();++it)
    {
        // 注意 Qt 的迭代器使用细节和 STL 略有差别. 此处不是使用 first / second 的方式
        unreadJson[it.key()] = it.value();
    }
    JsonObj["unread"] = unreadJson;

    // 写入到文件中
    QJsonDocument jsonDoc(JsonObj);
    QString s = jsonDoc.toJson();
    file.write(s.toUtf8());

    // 关闭文件
    file.close();
}

// 加载文件，在实例化的时候被执行,从本地加载
void datacenter::loadDataFile()
{
    // 确保在加载前文件是存在的，不存在需要进行初始化
    QString filePath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/ChatClient.json";

    QFileInfo fileInfo(filePath);
    if(!fileInfo.exists())
    {
        LOG_DEBUG << "文件不存在，进行初始化！";
        initDataFile();
    }

    // 文件存在，读取内容
    QFile file(filePath);
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        LOG_ERROR << "文件打开失败！" << file.errorString();
        return;
    }

    // 反序列化,读取到文件内容, 解析为 JSON 对象
    QJsonDocument jsonDoc = QJsonDocument::fromJson(file.readAll());
    if(jsonDoc.isNull())
    {
        LOG_ERROR << "解析 JSON 文件失败! JSON 文件格式有错误!";
        file.close();
        return;
    }

    QJsonObject jsonObj = jsonDoc.object();
    this->loginSessionId = jsonObj["loginSessionId"].toString();
    LOG_DEBUG << "loginSessionId= " << this->loginSessionId;

    this->unreadMessagesCount->clear();
    QJsonObject unreadJson = jsonObj["unread"].toObject();
    for(auto it = unreadJson.begin();it != unreadJson.end();++it)
    {
        this->unreadMessagesCount->insert(it.key(),it.value().toInt());
    }

    // 关闭文件
    file.close();
}

}// end namespace


